﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace XCSerialPort
{
    public class SerialPort_CH341_ISPManager : ISerialPortManager
    {
        private SerialPort _serialPort; // 串口对象

        public SerialPort_CH341_ISPManager() { }

        public SerialPort_CH341_ISPManager(ConfigType config)
        {
            _serialPort = new SerialPort
            {
                PortName = config.PortName, // 设置串口名称
                BaudRate = config.BaudRate, // 设置波特率
                DataBits = config.DataBits, // 设置数据位数
                StopBits = (System.IO.Ports.StopBits)config.StopBits, // 设置停止位
                Parity = (System.IO.Ports.Parity)config.Parity, // 设置奇偶校验
                ReadTimeout = 500, // 设置读取超时时间
                WriteTimeout = 500 // 设置写入超时时间
            };
        }

        /// <summary>
        /// 关闭串口并返回状态消息。
        /// </summary>
        /// <param name="msg">状态消息。</param>
        public void Close(out string msg)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Close(); // 关闭串口
                    msg = "串口关闭成功";
                }
                else
                {
                    msg = "串口已关闭";
                }
            }
            catch (Exception ex)
            {
                msg = "关闭串口失败: " + ex.Message; // 返回错误信息
            }
        }

        /// <summary>
        /// 获取所有可用串口的列表。
        /// </summary>
        /// <returns>串口名称的列表。</returns>
        public string[] GetSerialPorts(out string msg)
        {
            try
            {
                var ports = SerialPort.GetPortNames(); // 获取可用串口名称
                msg = "成功获取可用串口"; // 设置成功消息
                return ports; // 返回串口列表
            }
            catch (Exception ex)
            {
                msg = $"获取串口失败: {ex.Message}"; // 设置错误消息
                return Array.Empty<string>(); // 返回空数组
            }
        }

        /// <summary>
        /// 打开串口并返回状态消息。
        /// </summary>
        /// <param name="msg">状态消息。</param>
        /// <returns>成功打开串口则返回 true，否则返回 false。</returns>
        public bool Open(out string msg)
        {
            try
            {
                if (!_serialPort.IsOpen)
                {
                    _serialPort.Open(); // 打开串口
                }
                msg = "串口打开成功";
                return true;
            }
            catch (Exception ex)
            {
                msg = "打开串口失败: " + ex.Message; // 返回错误信息
                return false;
            }
        }

        public List<ulong> ReadRegister(ulong addr, out string msg, int length = 1, int timeoutMilliseconds = 150)
        {
            var results = new List<ulong>();
            StringBuilder messageBuilder = new StringBuilder();
            msg = "成功";

            try
            {
                for (int i = 0; i < length; i++)
                {
                    uint data = 0;
                    uint currentAddr = (uint)(addr + (ulong)i);
                    var status = ReadRegDataARM_New(currentAddr, ref data, timeoutMilliseconds);

                    if (status == 0x31) // 成功状态码
                    {
                        results.Add(data);
                        messageBuilder.AppendLine($"R: 0x{currentAddr:X8}, 0x{data:X2}");
                    }
                    else
                    {
                        msg = $"读取寄存器0x{currentAddr:X8}失败";
                    }
                }
            }
            catch (Exception ex)
            {
                msg = "读取寄存器失败: " + ex.Message;
                return new List<ulong>();
            }

            msg += messageBuilder.ToString();
            return results;
        }

        public void WriteRegister(ulong addr, List<ulong> values, out string msg, int length = 1, int timeoutMilliseconds = 150)
        {
            StringBuilder messageBuilder = new StringBuilder();
            msg = "成功";

            try
            {
                for (int i = 0; i < values.Count; i++)
                {
                    uint currentAddr = (uint)(addr + (ulong)i);
                    var status = SendRegDataARM_New(currentAddr, (uint)values[i]);
                    messageBuilder.AppendLine($"W: 0x{currentAddr:X8}, 0x{values[i]:X2}");

                    if (status != 0x21) // 成功状态码
                    {
                        msg = $"写入寄存器0x{currentAddr:X8}失败";
                    }
                }
            }
            catch (Exception ex)
            {
                msg = "写入寄存器失败: " + ex.Message;
            }

            msg += messageBuilder.ToString();
        }

        public byte SendRegDataARM_New(uint addr, uint data)
        {
            byte[] sendbuf = new byte[9];
            byte[] responseBuf = new byte[8];

            // 计算字节偏移量 (0-3)
            var byteIndex = (int)(addr % 4);

            // 构建发送数据包
            sendbuf[0] = 0x21; // 写命令
            sendbuf[1] = (byte)(addr & 0xFF);
            sendbuf[2] = (byte)((addr >> 8) & 0xFF);
            sendbuf[3] = (byte)((addr >> 16) & 0xFF);
            sendbuf[4] = (byte)((addr >> 24) & 0xFF);
            sendbuf[5 + byteIndex] = (byte)(data & 0xFF); // 数据位置

            // 发送并接收响应
            _serialPort.Write(sendbuf, 0, sendbuf.Length);

            // 读取响应（带超时）
            var sw = Stopwatch.StartNew();
            while (sw.ElapsedMilliseconds < 150 && _serialPort.BytesToRead < 1)
                Thread.Sleep(1);

            if (_serialPort.BytesToRead > 0)
                _serialPort.Read(responseBuf, 0, 1);

            return responseBuf[0];
        }

        public byte ReadRegDataARM_New(uint addr, ref uint data, int timeoutMilliseconds = 150)
        {
            byte[] txbuf = new byte[5];
            byte[] rxbuf = new byte[5];
            var byteIndex = (int)(addr % 4);

            // 构建请求包
            txbuf[0] = 0x31; // 读命令
            txbuf[1] = (byte)(addr & 0xFF);
            txbuf[2] = (byte)((addr >> 8) & 0xFF);
            txbuf[3] = (byte)((addr >> 16) & 0xFF);
            txbuf[4] = (byte)((addr >> 24) & 0xFF);

            // 清空缓冲区
            _serialPort.DiscardInBuffer();

            // 发送请求
            _serialPort.Write(txbuf, 0, txbuf.Length);

            // 接收响应（带超时）
            var sw = Stopwatch.StartNew();
            int bytesRead = 0;

            while (sw.ElapsedMilliseconds < timeoutMilliseconds)
            {
                if (_serialPort.BytesToRead >= 5)
                {
                    bytesRead = _serialPort.Read(rxbuf, 0, 5);
                    break;
                }
                Thread.Sleep(1);
            }

            // 处理响应
            if (bytesRead == 5 && rxbuf[0] == 0x31)
            {
                // 小端格式解析数据
                data = rxbuf[byteIndex + 1];
                return 0x31;
            }

            data = 0xFFFFFFFF;
            return 0xFF;
        }

        public bool DeviceStatus()
        {
            return true;
        }

        public void SetDeviceConfig(int _Index = 0, uint _deviceID = 0)
        {
            throw new NotImplementedException();
        }
    }
}
